import utils from '../utils'
import ShpConverterText from '../shpconverter-text'
import io from './index.js'
import {BufferReader} from './index.js'
import topojson from '../topjson'
import { GeoJSONParser, GeoJSONReader } from '../geojson'
import geojson from '../geojson'
import Data from '../data'

// Identify JSON type from the initial subset of a JSON string
function identifyJSONString(str, opts) {
  const maxChars = 1000
  let fmt = ''
  if (str.length > maxChars) str = str.substr(0, maxChars)
  str = str.replace(/\s/g, '')
  if (opts && opts.json_path) {
    fmt = 'json' // TODO: make json_path compatible with other types
  } else if (/^\[[{\]]/.test(str)) {
    // empty array or array of objects
    fmt = 'json'
  } else if (/"arcs":\[|"objects":\{|"transform":\{/.test(str)) {
    fmt =  'topojson'
  } else if (/^\{"/.test(str)) {
    fmt = 'geojson'
  }
  return fmt
}
function identifyJSONObject(o) {
  let fmt = null
  if (!o) {
    //
  } else if (o.type == 'Topology') {
    fmt = 'topojson'
  } else if (o.type) {
    fmt = 'geojson'
  } else if (utils.isArray(o)) {
    fmt = 'json'
  }
  return fmt
}
function importGeoJSONFile(fileReader, opts) {
  const importer = new GeoJSONParser(opts)
  new GeoJSONReader(fileReader).readObjects(importer.parseObject)
  return importer.done()
}
function importJSONFile(reader, opts) {
  const str = io.readFirstChars(reader, 1000)
  const type = identifyJSONString(str, opts)
  let dataset = null
  let retn = null
  if (type == 'geojson') { // consider only for larger files
    dataset = importGeoJSONFile(reader, opts)
    retn = {
      dataset: dataset,
      format: 'geojson'
    }
  } else {
    retn = {
      // content: cli.readFile(path, 'utf8')}
      content: reader.toString('utf8')
    }
  }
  reader.close()
  return retn
}
function importJSON(data, opts) {
  let content = data.content
  const filename = data.filename
  const retn = {filename}
  let reader = null
  if (!content) {
    reader = new FileReader(filename)
  } else if (content instanceof ArrayBuffer) {
    if (content.byteLength < 1e7) {
      content = ShpConverterText.bufferToString(utils.createBuffer(content))
    } else {
      reader = new BufferReader(content)
      content = null
    }
  }
  if (reader) {
    data = importJSONFile(reader, opts)
    if (data.dataset) {
      retn.dataset = data.dataset
      retn.format = data.format
    } else {
      content = data.content
    }
  }
  if (content) {
    if (utils.isString(content)) {
      try {
        content = JSON.parse(content)
      } catch (e) {
        utils.error(`Unable to parse JSON`)
      }
    }
    if (opts.json_path) {
      content = selectFromObject(content, opts.json_path)
    }
    retn.format = identifyJSONObject(content, opts)
    if (retn.format == 'topojson') {
      retn.dataset = topojson.importTopoJSON(content, opts)
    } else if (retn.format == 'geojson') {
      retn.dataset = geojson.importGeoJSON(content, opts)
    } else if (retn.format == 'json') {
      retn.dataset = Data.importJSONTable(content, opts)
    } else {
      utils.error("Unknown JSON format")
    }
  }
  return retn
}
function selectFromObject(o, path) {
  const parts = path.split('.')
  const value = o && o[parts[0]]
  if (parts > 1) {
    return selectFromObject(value, parts.slice(1).join(''))
  }
  return value
}

export default {
  importJSON,
}